package MDVRPTW;

import java.util.ArrayList;
import java.util.Random;

public class MOSA {
	private int totalCount = 10000; // 总迭代次数

	private double initTmp = 10000;// 初温

	private double alpha = 0.99;// 降温系数

	private int innerCount = 60; // 内循环次数

	private Population pop;

	private double rencTmp; // 当前温度

	private MDVRPTW top;

	public MOSA(MDVRPTW top) {
		this.pop = new Population();
		this.top = top;
		this.rencTmp = this.initTmp;
	}

	public Population getPop() {
		return this.pop;
	}
	//初始化
	public void initial() {
		this.pop.getParetoSet().add(this.top.init());
	}
	
	private Solution localSearch(Solution s) {
		Solution temp;
		temp = this.top.neighbor(s);
		//temp.print();
		this.updateControl(temp);
		return temp;
	}

	private void updateControl(Solution s) {
		int size = this.pop.getParetoSet().size();
		int counter;
		counter = 0;
		for (int i = 0; i < size; i++) {
			if (this.pop.campare(this.pop.getParetoSet().get(i), s) == 1) {
				counter++;
			}
		}
		s.setNumControl(counter);
	}
	
	private void innerIter() {
		Random random=new Random();
		int counter;
		int delta;
		Solution s, temp;
		s = new Solution(this.pop.getParetoSet().get(
				random.nextInt(this.pop.getParetoSet().size())));
		counter = 0;
		while (counter < this.innerCount) {
			counter++;
			temp = this.localSearch(s);
			if (temp.getNumControl() == 0) {
				this.pop.updatePareto(temp);
			}
			delta = s.getNumControl() - temp.getNumControl();
			if (delta > 0) {// 之前的适应度值比现在大，即现在的解比之前的要好
				s = temp;
			} else {
				// 若exp(-(fj-fi)/tmp)>random()，则也接受（random()为0至1中的一个随机数）
				double p = Math.exp(delta / this.rencTmp);
				double r = random.nextDouble();
				if (r < p) {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
					s = temp;
				}
			}
		}
	}

	public void iteration() {
		this.innerIter();
		this.rencTmp *= this.alpha;
	}

	public Population run(int tCount,int iCount) {
		this.totalCount=tCount;
		this.innerCount=iCount;
		int iter;
		iter = 0;
		while (iter < this.totalCount) {
			this.iteration();
			iter++;
		}
		return this.getPop();
	}
	
	public void run() {
		int iter;
		iter = 0;
		while (iter < this.totalCount) {
			this.iteration();
			iter++;
			//System.out.println(iter + "th, " + this.rencTmp + ", " + this.pop.getParetoSet().size());
		}
		ArrayList<Solution> pops=this.pop.getParetoSet();
		int n=pops.size();
		double totalCars=0;
		double totalDistance=0.0;
		double totalVoilation=0.0;
		double timeVariance=0.0;
		for (Solution solution : pops) {
			totalCars+=solution.getTotalCars();
			totalVoilation+=solution.getTotalVoilation();
			totalDistance+=solution.getTotalDistance();
			timeVariance+=solution.getTimeVariance();
		}
		totalCars=(double)totalCars/n;
		totalVoilation=totalVoilation/n;
		totalDistance=totalDistance/n;
		timeVariance=timeVariance/n;
		System.out.println(totalCars+"  "+totalDistance+"  "+totalVoilation+"  "+timeVariance);
	}
}
